package cn.gailvlun.gll.chatkit.record;


import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.graphics.Rect;
import android.os.IBinder;
import android.support.v7.widget.AppCompatButton;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

import com.blankj.utilcode.util.FileUtils;

import java.io.File;
import java.util.concurrent.TimeUnit;

import cn.gailvlun.gll.chatkit.R;
import cn.gailvlun.gll.chatkit.message.OnVoiceSuccessListener;
import cn.gailvlun.gll.util.LogUtil;
import cn.gailvlun.gll.util.RxUtil;
import cn.gailvlun.gll.util.ToastUtil;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;



public class RecordButton extends AppCompatButton {
    public RecordButton(Context context) {
        this(context, null);
    }

    public RecordButton(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RecordButton(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        Intent intent = new Intent(getContext(), cn.gailvlun.gll.chatkit.RecordService.class);
        getContext().bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
        setClickable(true);
    }

    @Override
    protected void onDetachedFromWindow() {
        getContext().unbindService(serviceConnection);
        super.onDetachedFromWindow();
    }

    public enum RecordState {
        IDLE, RECORDING, CANCELLING, SHORT, COUNT_DOWN
    }
    private RecordState mRecordState = RecordState.IDLE;
    private IRecordView mRecordView;
    private boolean isRecording = false;

    private cn.gailvlun.gll.chatkit.RecordService.DemoBinder mBinder = null;

    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mBinder = (cn.gailvlun.gll.chatkit.RecordService.DemoBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mBinder = null;
        }
    };

    public void setRecordView(IRecordView recordView) {
        mRecordView = recordView;
    }

    private void setRecordState(RecordState state) {
        mRecordState = state;
        switch (state) {
            case IDLE: {
                setText("按住说话");
                setTextColor(getResources().getColor(R.color.battleshipGrey));
                setBackgroundResource(R.drawable.rounded_pale_grey);
                if (mRecordView != null) {
                    mRecordView.setVoiceState(RecordState.IDLE);
                }
                break;
            }
            case RECORDING: {
                setText("松开结束");
                setTextColor(getResources().getColor(R.color.cloudyBlue));
                setBackgroundResource(R.drawable.rounded_pale_grey_three);
                if (mRecordView != null) {
                    mRecordView.setVoiceState(RecordState.RECORDING);
                }
                break;
            }
            case CANCELLING: {
                setText("松开取消");
                if (mRecordView != null) {
                    mRecordView.setVoiceState(RecordState.CANCELLING);
                }
                break;
            }
            case SHORT: {
                setText("按住说话");
                if (mRecordView != null) {
                    mRecordView.setVoiceState(RecordState.SHORT);
                    RxUtil.timer(SHORT_SHOW_TIME, TimeUnit.MILLISECONDS)
                            .subscribe(new Consumer<Long>() {
                                @Override
                                public void accept(Long aLong) throws Exception {
                                    setRecordState(RecordState.IDLE);

                                }
                            });
                }
                break;
            }
        }
    }

    
    private static int MIN_RECORD_TIME = 500;
    
    private static int SHORT_SHOW_TIME = 500;
    
    private static int HEIGHT_REGION = 200;

    private long mStartTime;
    private boolean hasPermission = false;
    private long lastClickTime = System.currentTimeMillis();

    
    private static long CLICK_THROTTLE = 1000;
    
    private static int MAX_VOLUME_RATE = 3;
    
    private static int MAX_RECORD_TIME = 60;

    public void setHasPermission(boolean hasPermission) {
        this.hasPermission = hasPermission;
    }

    public boolean isHasPermission() {
        return hasPermission;
    }

    public void checkIsFileExits() {
        RxUtil.timer(500, TimeUnit.MILLISECONDS)
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {

                        if (!FileUtils.isFileExists(mBinder.getCurrentFile())) {
                            cancelRecord();
                            setRecordState(RecordState.SHORT);
                            return;
                        }

                        if (System.currentTimeMillis() - startTime > 800) {
                            cancelRecord();
                            setRecordState(RecordState.SHORT);
                        }
                    }
                });
    }

    private long startTime;

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (hasPermission) {
            int x = (int) event.getX();
            int y = (int) event.getY();

            LogUtil.d("x: " + x + ", y: " + y + "action: " + event.getAction());
            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    long thisClickTime = System.currentTimeMillis();
                    if (thisClickTime - lastClickTime >= CLICK_THROTTLE) {
                        lastClickTime = thisClickTime;
                        mStartTime = System.currentTimeMillis();
                        setRecordState(RecordState.RECORDING);
                        checkIsFileExits();
                        startTime = System.currentTimeMillis();
                        startRecord();
                    } else {
                        return true;
                    }
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    if (!isRecording) {
                        return true;
                    }
                    if (isWantCancel(x, y)) {
                        setRecordState(RecordState.CANCELLING);
                    } else {
                        setRecordState(RecordState.RECORDING);
                    }
                    break;
                }
                case MotionEvent.ACTION_UP: {
                    if (isWantCancel(x, y)) {
                        
                        cancelRecord();
                        setRecordState(RecordState.IDLE);
                    } else {
                        if (isTooShort()) {
                            
                            cancelRecord();
                            setRecordState(RecordState.SHORT);
                        } else {
                            
                            stopRecord();
                            setRecordState(RecordState.IDLE);
                        }
                    }
                    break;
                }
            }
        } else {
            ToastUtil.showShort("没有录音权限");
        }
        return super.onTouchEvent(event);
    }

    private Disposable countDownDisposable;

    
    public void startRecord() {
        if (!isRecording) {
            startCountDown();
            LogUtil.d("startRecord");
            mBinder.startRecord();
            updateVolumeRate();
            isRecording = true;
        }
    }

    
    public File stopRecord() {
        if (isRecording) {
            stopCountDown();
            stopVolumeRate();
            mBinder.stopRecord();
            if (FileUtils.getFileLength(mBinder.getCurrentFile()) > 0) {
                if (mOnVoiceSuccessListener != null) {
                    mOnVoiceSuccessListener.onVoiceSuccess(mBinder.getCurrentFile());
                }
            }
            isRecording = false;
            return null;
        }
        return null;
    }

    
    public void cancelRecord() {
        if (isRecording) {
            stopCountDown();
            stopVolumeRate();
            mBinder.cancelRecord();
            isRecording = false;
        }
    }

    private void startCountDown() {
        countDownDisposable = RxUtil.countDown(MAX_RECORD_TIME)
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        if (aLong <= 10 && mRecordView != null) {
                            mRecordView.setCountDown(aLong);
                        }
                        if (aLong == 0) {
                            stopRecord();
                            setRecordState(RecordState.IDLE);
                        }
                    }
                });
    }

    private void stopCountDown() {
        if (countDownDisposable != null) {
            if (!countDownDisposable.isDisposed()) {
                countDownDisposable.dispose();
            }
            countDownDisposable = null;
        }
    }

    private Disposable volumeDisposable;

    private void updateVolumeRate() {
        volumeDisposable = Observable.interval(0, 100, TimeUnit.MILLISECONDS)
                .compose(RxUtil.<Long>applyScheduler())
                .subscribe(new Consumer<Long>() {
                    @Override
                    public void accept(Long aLong) throws Exception {
                        if (mBinder != null) {
                            int volumeRate = mBinder.getVolumeRate();
                            if (volumeRate != -1) {
                                mRecordView.setVoiceLevel(MAX_VOLUME_RATE * volumeRate / 32768 + 1);
                            }
                        }
                    }
                });
    }

    private void stopVolumeRate() {
        if (volumeDisposable != null) {
            if (!volumeDisposable.isDisposed()) {
                volumeDisposable.dispose();
            }
            volumeDisposable = null;
        }
    }

    private boolean isWantCancel(int x, int y) {
        if (y <= getTop() - HEIGHT_REGION || y >= getTop() + getHeight() + HEIGHT_REGION) {
            return true;
        }
        return false;
    }

    private boolean isTooShort() {
        if (System.currentTimeMillis() - mStartTime < MIN_RECORD_TIME) {
            return true;
        }
        return false;
    }

    private OnVoiceSuccessListener mOnVoiceSuccessListener;

    public void setOnVoiceSuccessListener(OnVoiceSuccessListener onVoiceSuccessListener) {
        this.mOnVoiceSuccessListener = onVoiceSuccessListener;
    }
}
